package com.weifly.weistock.trade.monitor.impl;

import com.weifly.weistock.core.event.AbstractEventService;
import com.weifly.weistock.core.event.StockEventEnum;
import com.weifly.weistock.trade.config.AccountConfigDto;
import com.weifly.weistock.trade.config.AllStockConfig;
import com.weifly.weistock.trade.config.StockConfigDto;
import com.weifly.weistock.trade.config.StockConfigService;
import com.weifly.weistock.core.task.UpdateStatus;
import com.weifly.weistock.core.task.AbstractUpdateService;
import com.weifly.weistock.trade.monitor.StockMonitorDto;
import com.weifly.weistock.trade.monitor.vo.MessageVO;
import com.weifly.weistock.trade.monitor.vo.OrderVO;
import com.weifly.weistock.trade.monitor.vo.StatusVO;
import com.weifly.weistock.trade.monitor.vo.StockVO;
import com.weifly.weistock.trade.trade.StockOrderInfo;
import com.weifly.weistock.trade.monitor.StockMonitorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.PropertyChangeListener;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 股票监听服务实现
 *
 * @author weifly
 * @since 2018/10/31
 */
public class StockMonitorServiceImpl extends AbstractEventService implements StockMonitorService {

    private Logger log = LoggerFactory.getLogger(StockMonitorServiceImpl.class);
    private SimpleDateFormat timeSdf = new SimpleDateFormat("HH:mm:ss");

    private int status = AbstractUpdateService.STATUS_INIT; // 状态
    private String date; // 交易日期
    private String time; // 更新时间

    private AccountConfigDto accountConfig; // 股票账号
    private List<StockMonitorDto> stockList = new ArrayList<>(); // 股票监控列表
    private List<MessageVO> messageList = new ArrayList<>(); // 日志消息列表

    private StockConfigService stockConfigService;

    public void setStockConfigService(StockConfigService stockConfigService) {
        this.stockConfigService = stockConfigService;
    }

    @Override
    public synchronized void updateAccountConfig(AccountConfigDto accountConfig, boolean save) {
        this.accountConfig = accountConfig;
        if(save){
            this.saveConfigInner();
        }
        this.fireStockEventChange(StockEventEnum.UPDATE_ACCOUNT, null, accountConfig);
    }

    @Override
    public synchronized AccountConfigDto getAccountConfig() {
        return this.accountConfig;
    }

    @Override
    public synchronized void addAccountConfigListener(PropertyChangeListener listener) {
        this.addStockEventListener(StockEventEnum.UPDATE_ACCOUNT, listener);
    }

    @Override
    public void updateStockConfigList(List<StockConfigDto> stockConfigList, boolean save) {
        this.stockList.clear();
        if(stockConfigList!=null){
            for(StockConfigDto stockConfig : stockConfigList){
                StockMonitorDto monitorDto = new StockMonitorDto();
                monitorDto.setStockConfig(stockConfig);
                this.stockList.add(monitorDto);
            }
        }
        if(save){
            this.saveConfigInner();
        }
        this.fireStockEventChange(StockEventEnum.UPDATE_STOCK_BY_USER, null, this.stockList);
    }

    public synchronized void updateStockConfig(StockConfigDto stockConfig) {
        int targetIdx = -1;
        for(int i=0;i<this.stockList.size();i++){
            if(this.stockList.get(i).getStockConfig().getStockCode().equals(stockConfig.getStockCode())){
                targetIdx = i;
                StockMonitorDto monitorDto = new StockMonitorDto();
                monitorDto.setStockConfig(stockConfig);
                this.stockList.set(i, monitorDto);
                break;
            }
        }
        if(targetIdx==-1){
            StockMonitorDto monitorDto = new StockMonitorDto();
            monitorDto.setStockConfig(stockConfig);
            this.stockList.add(monitorDto);
        }

        this.saveConfig();
        this.fireStockEventChange(StockEventEnum.UPDATE_STOCK_BY_USER, null, this.stockList);
    }

    @Override
    public synchronized void clearStockMonitorInfo() {
        for(StockMonitorDto stockInfo : this.stockList){
            stockInfo.setNewestPrice(null);
            stockInfo.setNewestPriceUpdateTime(null);
            stockInfo.getPriceList().clear();
            stockInfo.setBuyOrderInfo(null);
            stockInfo.setBuyOrderUpdateTime(null);
            stockInfo.setSellOrderInfo(null);
            stockInfo.setSellOrderUpdateTime(null);
        }
    }

    public synchronized List<StockMonitorDto> getStockList() {
        List<StockMonitorDto> allStocks = new ArrayList<>();
        allStocks.addAll(this.stockList);
        return allStocks;
    }

    @Override
    public synchronized void addStockMonitorListener(PropertyChangeListener listener) {
        this.addStockEventListener(StockEventEnum.UPDATE_STOCK_BY_USER, listener);
        this.addStockEventListener(StockEventEnum.UPDATE_STOCK_BY_TASK, listener);
    }

    @Override
    public void fireStockListChange() {
        this.fireStockEventChange(StockEventEnum.UPDATE_STOCK_BY_TASK, null, this.stockList);
    }

    /**
     * 更新状态信息
     */
    public synchronized void updateStatus(UpdateStatus status){
        this.status = status.getStatus();
        this.date = status.makeDateString();
        this.time = status.makeTimeString();
    }

    public synchronized StatusVO calcMonitorInfo() {
        StatusVO statusVO = new StatusVO();
        statusVO.setStatus(this.status);
        statusVO.setDate(this.date);
        statusVO.setTime(this.time);

        List<StockVO> dataList = new ArrayList<>();
        for(StockMonitorDto stockInfo : this.stockList){
            StockVO dataInfo = new StockVO();
            dataInfo.setStockCode(stockInfo.getStockConfig().getStockCode());
            dataInfo.setStockName(stockInfo.getStockConfig().getStockName());
            if(stockInfo.getNewestPrice()!=null){
                dataInfo.setNewestPrice(stockInfo.getNewestPrice());
            }
            if(stockInfo.getStockConfig().getBasePrice()!=null){
                dataInfo.setBasePrice(stockInfo.getStockConfig().getBasePrice());
            }

            // 买入委托
            if(stockInfo.getBuyOrderInfo()!=null){
                OrderVO buyInfo = new OrderVO();
                StockOrderInfo orderInfo = stockInfo.getBuyOrderInfo();
                buyInfo.setOrderNumber(orderInfo.getOrderNumber());
                buyInfo.setEntrustPrice(orderInfo.getEntrustPrice());
                buyInfo.setOrderTime(this.timeSdf.format(new Date(orderInfo.getOrderTime())));
                dataInfo.setBuyInfo(buyInfo);
            }

            // 卖出委托
            if(stockInfo.getSellOrderInfo()!=null){
                OrderVO sellInfo = new OrderVO();
                StockOrderInfo orderInfo = stockInfo.getSellOrderInfo();
                sellInfo.setOrderNumber(orderInfo.getOrderNumber());
                sellInfo.setEntrustPrice(orderInfo.getEntrustPrice());
                sellInfo.setOrderTime(this.timeSdf.format(new Date(orderInfo.getOrderTime())));
                dataInfo.setSellInfo(sellInfo);
            }

            dataList.add(dataInfo);
        }
        statusVO.setStockList(dataList);

        List<MessageVO> msgList = new ArrayList<>();
        msgList.addAll(this.messageList);
        statusVO.setMessageList(msgList);

        return statusVO;
    }

    @Override
    public synchronized void saveConfig() {
        this.saveConfigInner();
        this.fireStockEventChange(StockEventEnum.UPDATE_STOCK_BY_TASK, null, this.stockList);
    }

    @Override
    public synchronized void writeMessage(String message) {
        log.info(message);
        MessageVO vo = new MessageVO();
        vo.setTime(this.timeSdf.format(new Date()));
        vo.setMessage(message);

        messageList.add(vo);
        if(messageList.size()>20){
            messageList.remove(0);
        }
    }

    private void saveConfigInner(){
        AllStockConfig allStockConfig = new AllStockConfig();
        allStockConfig.setAccountConfig(this.accountConfig);
        List<StockConfigDto> stockConfigList = new ArrayList<>();
        for(StockMonitorDto monitorDto : this.stockList){
            stockConfigList.add(monitorDto.getStockConfig());
        }
        allStockConfig.setStockConfigList(stockConfigList);
        this.stockConfigService.saveConfig(allStockConfig);
    }
}
